#!/usr/bin/env python
import socket
import os,sys
import json
import argparse
import logging

class Handler:
    """
        2001 -- json format error
        2002 -- json field error
        2003 -- cmd not defined
    """

    def __init__(self,service):
        self.__service=service

        self.__cmd_dicts={"list":self.list,"add":self.add,"get":self.get}

        self.__jsonstr=None
        self.__cmd=None
        self.__data=None
    
    def __check_cmd(self):
        if self.__cmd in self.__cmd_dicts:
            return True

        return False

    def list(self,data):
        return self.__service.list(data)

    def add(self,data):
        return self.__service.add(data)

    def get(self,data):
        return self.__service.get(data)

    def __coding(self,return_code,data):
        data = {"code":return_code,"data":data}
        return json.dumps(data)

    def __execute(self):
        try:
            jsonob=json.loads(self.__jsonstr)
        except:
            return self.__coding("2001", None)

        try:
            self.__cmd=jsonob["cmd"]
            self.__data=jsonob["data"]
        except:
            return self.__coding("2002", None)

        if self.__check_cmd():
            code,result = self.__cmd_dicts[self.__cmd](self.__data)
        else:
            return self.__coding("2003", None)

        return self.__coding(code, result)

    def __call__(self,jsonstr):
        self.__jsonstr=jsonstr
        return self.__execute()


class DirCache:
    """
        301 -- dir path is null
        302 -- no such the dir id
        303 -- ignore .. . null
        304 -- no such dir path
    """

    def __init__(self,size):
        self.__size=size
        self.__cache={}
        """
            example
            {
                "/home/kong":0,
                "/home/kong/RAM":1
            }
        """
        self.__index=[]

    def add(self,path):
        if not os.path.exists(path):
            print "no such dir path:%s" % path
            return 304,None

        if path in ("..",".","/"):
            print "ignore dir .. . /"
            return 303,None

        print "path:%s" % path,

        if not path:
            print "value:error"
            return 301,None
        else:
            print "value:ok",
        

        if path.endswith("/"):
            print "has/:yes",
            path=path[:-1]
        else:
            print "has/:no",


        if path in self.__cache:
            print "exist:yes",
            self.__cache[path]+=1
        else:
            length=len(self.__cache)
            print "size:%s" % length,

            if length >=self.__size:
                print "oversize:yes",
                print "pop:%s" % self.__index[-1][0],
                self.__cache.pop(self.__index[-1][0])
            else:
                print "oversize:no",
                print "pop:null",

            print "exist:no",
            self.__cache[path]=1 if not self.__cache else max(self.__cache.values())+1

        self.__index = sorted(self.__cache.iteritems(), key=lambda d:d[1], reverse = True)
        print "hit:%s" % str(self.__cache[path])

        return 200,None

    def list(self,undefine):
        return 200,self.__index

    def get(self,id):
        try:
            tmp=self.__index[id-1]
            return 200,tmp[0]
        except IndexError:
            return 302,None

def server(sockpath,handler):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    if os.path.exists(sockpath):
        os.unlink(sockpath)
    sock.bind(sockpath)
    sock.listen(5)
    
    while 1:
        connection,address = sock.accept()
        try:
            connection.send(handler(connection.recv(1024)))
        except socket.error:
            pass
        finally:
            connection.close()


class MyFormat(argparse.HelpFormatter):
    def _format_actions_usage(self, actions, groups):
        return argparse.HelpFormatter._format_actions_usage(self, actions, groups).lower()

    def _format_action_invocation(self, action):
        return argparse.HelpFormatter._format_action_invocation(self, action).lower()

def execute_args():
    parser = argparse.ArgumentParser(description='dircached help',formatter_class=MyFormat)

    parser.add_argument('-l', action="store",default=5,type=int,dest="size",help="cache size default:5")
    parser.add_argument('-s', action="store",default="/tmp/dircached.sock",dest="sock",help="unix sock default:/tmp/dircached.sock")
    parser.add_argument('-f', action="store_true",default=False,dest="background",help="run in background default:false")
    parser.add_argument('-p', action="store",dest="pidfile",help="create pid file")

    return parser

def execute_command(args=sys.argv[1:]):
    a = execute_args().parse_args(args)
    h=Handler(DirCache(a.size))

    if a.background:
        try:
            pid = os.fork()
            if pid > 0:
                print "daemon pid %s" % pid
                return

        except :
            sys.exit(1)

    pid=os.getpid()
    if a.pidfile:
        try:
            f=open(a.pidfile,'w')
            f.write(str(pid))
            f.flush()
            f.close()
        except:
            print "can not create pid file"
            sys.exit(1)

    server(a.sock, h)

if __name__ == '__main__':
    reload(sys)
    sys.setdefaultencoding("utf-8")
    try:
        execute_command()
        sys.exit(0)
    except KeyboardInterrupt:
        print "bye!"